﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Dts.Runtime; // Requires reference to Microsoft.SQLServer.ManagedDTS

namespace ToddMcDermid.SSIS
{
    // This attribute tells SSIS about your Task.
    [DtsTask(
        DisplayName = "Send HTML Mail Task",
        TaskType = "General",
        TaskContact = "Todd McDermid",
        UITypeName = "ToddMcDermid.SSIS.SendHTMLMailTaskInterface,SendHTMLMailTask90,Version=1.0.0.0,Culture = Neutral,PublicKeyToken = 6c005605b216cf47",
        IconResource = "ToddMcDermid.SSIS.SendHTMLMailTask.ico",
        RequiredProductLevel = DTSProductLevel.None)]
    public class SendHTMLMailTask : Task
    {
        #region Public Enumerations
        public enum BodyContentType
        {
            PlainText,
            HTML
        }

        public enum BodySourceType
        {
            Direct,
            FromVariable
        }
        #endregion

        #region Private Variables
        private string _smtpConnectionID;
        private string _fromAddress;
        private string _replyToAddress;
        /// <summary>List of email addresses, separated by semi-colons</summary>
        private string _toAddresses;
        /// <summary>List of email addresses, separated by semi-colons</summary>
        private string _ccAddresses;
        /// <summary>List of email addresses, separated by semi-colons</summary>
        private string _bccAddresses;
        private string _subject;
        private BodyContentType _bodyContentType;
        private BodySourceType _bodySourceType;
        private string _body;
        /// <summary>List of file attachments, separated by semi-colons</summary>
        private string _attachments;
        private System.Net.Mail.MailPriority _priority;

        #endregion

        #region Constructor
        public SendHTMLMailTask()
        {
            this._fromAddress = "";
            this._replyToAddress = "";
            this._toAddresses = "";
            this._ccAddresses = "";
            this._bccAddresses = "";
            this._subject = "";
            this._body = "";
            this._bodyContentType = BodyContentType.HTML;
            this._bodySourceType = BodySourceType.Direct;
            this._attachments = "";
            this._priority = System.Net.Mail.MailPriority.Normal;
        }
        #endregion

        #region Public Properties
        public string SmtpConnectionManagerID
        {
            get { return this._smtpConnectionID; }
            set { this._smtpConnectionID = value; }
        }

        public string FromAddress
        {
            get { return this._fromAddress; }
            set { this._fromAddress = value; }
        }

        public string ReplyToAddress
        {
            get { return this._replyToAddress; }
            set { this._replyToAddress = value; }
        }

        public string ToAddresses
        {
            get { return this._toAddresses; }
            set { this._toAddresses = value; }
        }

        public string CCAddresses
        {
            get { return this._ccAddresses; }
            set { this._ccAddresses = value; }
        }

        public string BCCAddresses
        {
            get { return this._bccAddresses; }
            set { this._bccAddresses = value; }
        }

        public string Subject
        {
            get { return this._subject; }
            set { this._subject = value; }
        }

        public string Body
        {
            get { return this._body; }
            set { this._body = value; }
        }

        public BodyContentType BodyContent
        {
            get { return this._bodyContentType; }
            set { this._bodyContentType = value; }
        }

        public BodySourceType BodySource
        {
            get { return this._bodySourceType; }
            set { this._bodySourceType = value; }
        }

        public string Attachments
        {
            get { return this._attachments; }
            set { this._attachments = value; }
        }

        public System.Net.Mail.MailPriority Priority
        {
            get { return this._priority; }
            set { this._priority = value; }
        }
        #endregion

        #region Task Implementation
        #region Validate
        /// <summary>
        /// This method is called frequently at design time and runtime.  It's purpose is
        /// to tell SSIS if "everything is OK".  You should check that any SSIS variables
        /// you will use at runtime actually exist in the VariableDispenser, that they're 
        /// the right type, and contain valid values.  You should check that any connections
        /// you intend to use exist in the Connections collection, and that you can connect
        /// to them.
        /// </summary>
        public override DTSExecResult Validate(Connections connections, VariableDispenser variableDispenser, 
            IDTSComponentEvents componentEvents, IDTSLogging log)
        {
            DTSExecResult result = base.Validate(connections, variableDispenser, componentEvents, log);

            if (result == DTSExecResult.Success)
            {
                try
                {
                    #region Validate Connection Manager
                    try
                    {
                        if ((this._smtpConnectionID == null) || (this._smtpConnectionID == ""))
                        {
                            componentEvents.FireError(0, "", "No Connection Manager specified.", "", 0);
                            result = DTSExecResult.Failure;
                        }
                        else
                        {
                            ConnectionManager smtp = connections[this._smtpConnectionID];
                            if (smtp.CreationName != "SMTP")
                            {
                                componentEvents.FireError(0, "", "Connection Manager " + smtp.Name + " is not an SMTP Connection Manager.", "", 0);
                                result = DTSExecResult.Failure;
                            }
                        }
                    }
                    #region catch ...
                    catch (Exception ex)
                    {
                        componentEvents.FireError(0, "", "Connection Manager " + this._smtpConnectionID + " can not be found: " + ex.Message, "", 0);
                        result = DTSExecResult.Failure;
                    }
                    #endregion
                    #endregion

                    #region Validate From
                    if ((this._fromAddress == null) || (this._fromAddress.Length == 0))
                    {
                        componentEvents.FireError(0, "", "'From' address must be specified.", "", 0);
                        result = DTSExecResult.Failure;
                    }
                    else
                    {
                        try
                        {
                            System.Net.Mail.MailAddress from = new System.Net.Mail.MailAddress(this._fromAddress);
                        }
                        #region catch ...
                        catch (Exception ex)
                        {
                            componentEvents.FireError(0, "", "'" + this._fromAddress + "' is not a valid 'from' mail address: " + ex.Message + ".", "", 0);
                            result = DTSExecResult.Failure;
                        }
                        #endregion
                    }
                    #endregion

                    #region Validate Reply To
                    if ((this._replyToAddress != null) && (this._replyToAddress.Length > 0))
                    {
                        try
                        {
                            System.Net.Mail.MailAddress replyTo = new System.Net.Mail.MailAddress(this._replyToAddress);
                        }
                        #region catch ...
                        catch (Exception ex)
                        {
                            componentEvents.FireError(0, "", "'" + this._replyToAddress + "' is not a valid 'reply to' mail address: " + ex.Message + ".", "", 0);
                            result = DTSExecResult.Failure;
                        }
                        #endregion
                    }
                    #endregion

                    #region Validate To
                    if ((this._toAddresses == null) || (this._toAddresses.Length == 0))
                    {
                        componentEvents.FireError(0, "", "'To' address(es) must be specified.", "", 0);
                        result = DTSExecResult.Failure;
                    }
                    else
                    {
                        string[] toAddressArray = this._toAddresses.Split(';');
                        foreach (string toAddress in toAddressArray)
                        {
                            try
                            {
                                System.Net.Mail.MailAddress to = new System.Net.Mail.MailAddress(toAddress);
                            }
                            #region catch ...
                            catch (Exception ex)
                            {
                                componentEvents.FireError(0, "", "'" + toAddress + "' is not a valid 'to' mail address: " + ex.Message + ".", "", 0);
                                result = DTSExecResult.Failure;
                            }
                            #endregion
                        }
                    }
                    #endregion

                    #region Validate CC
                    if ((this._ccAddresses != null) && (this._ccAddresses.Length > 0))
                    {
                        string[] ccAddressArray = this._ccAddresses.Split(';');
                        foreach (string ccAddress in ccAddressArray)
                        {
                            try
                            {
                                System.Net.Mail.MailAddress cc = new System.Net.Mail.MailAddress(ccAddress);
                            }
                            #region catch ...
                            catch (Exception ex)
                            {
                                componentEvents.FireError(0, "", "'" + ccAddress + "' is not a valid 'cc' mail address: " + ex.Message + ".", "", 0);
                                result = DTSExecResult.Failure;
                            }
                            #endregion
                        }
                    }
                    #endregion

                    #region Validate BCC
                    if ((this._bccAddresses != null) && (this._bccAddresses.Length > 0))
                    {
                        string[] bccAddressArray = this._bccAddresses.Split(';');
                        foreach (string bccAddress in bccAddressArray)
                        {
                            try
                            {
                                System.Net.Mail.MailAddress bcc = new System.Net.Mail.MailAddress(bccAddress);
                            }
                            #region catch ...
                            catch (Exception ex)
                            {
                                componentEvents.FireError(0, "", "'" + bccAddress + "' is not a valid 'bcc' mail address: " + ex.Message + ".", "", 0);
                                result = DTSExecResult.Failure;
                            }
                            #endregion
                        }
                    }
                    #endregion

                    #region Validate Subject
                    if ((this._subject == null) || (this._subject.Length == 0))
                    {
                        componentEvents.FireError(0, "", "A subject must be specified.", "", 0);
                        result = DTSExecResult.Failure;
                    }
                    #endregion

                    #region Validate Body
                    if ((this._body == null) || (this._body.Length == 0))
                    {
                        componentEvents.FireError(0, "", "A body must be specified.", "", 0);
                        result = DTSExecResult.Failure;
                    }
                    if (this._bodySourceType == BodySourceType.FromVariable)
                    {
                        if (!variableDispenser.Contains(this._body))
                        {
                            componentEvents.FireError(0, "", "The variable '" + this._body + "' specified for the body does not exist.", "", 0);
                            result = DTSExecResult.Failure;
                        }
                        else
                        {
                            Variables vars = null;
                            variableDispenser.LockForRead(this._body);
                            variableDispenser.GetVariables(ref vars);
                            if (vars[0].DataType != TypeCode.String)
                            {
                                componentEvents.FireError(0, "", "The variable '" + this._body + "' is not a String type.", "", 0);
                                result = DTSExecResult.Failure;
                            }
                            vars.Unlock();
                        }
                    }
                    #endregion

                    #region Validate Attachments
                    if ((this._attachments != null) && (this._attachments.Length > 0))
                    {
                        string[] attachmentArray = this._attachments.Split(';');
                        foreach (string attachment in attachmentArray)
                        {
                            if (!System.IO.File.Exists(attachment))
                            {
                                componentEvents.FireError(0, "", "Attachment '" + attachment + "' does not exist.", "", 0);
                                result = DTSExecResult.Failure;
                            }
                        }
                    }
                    #endregion
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "", "Validation error: " + ex.Message + ".", "", 0);
                    result = DTSExecResult.Failure;
                }
                #endregion
            }
            return result;
        }
        #endregion

        #region Execute
        /// <summary>
        /// This method is called only at runtime, and does all the "work".  It's roughly
        /// equivalent to the contents of your Script Task code.
        /// </summary>
        public override DTSExecResult Execute(Connections connections, VariableDispenser variableDispenser, IDTSComponentEvents componentEvents, IDTSLogging log, object transaction)
        {
            // Assume failure
            DTSExecResult result = DTSExecResult.Failure;

            try
            {
                System.Net.Mail.MailMessage mailMessage = new System.Net.Mail.MailMessage();

                #region Add "from" address
                try
                {
                    mailMessage.From = new System.Net.Mail.MailAddress(this._fromAddress);
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring 'from' address: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Add "reply to" address
                try
                {
                    if (this._replyToAddress != "")
                    {
                        mailMessage.ReplyTo = new System.Net.Mail.MailAddress(this._replyToAddress);
                    }
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring 'reply to' address: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Add list of "to" addresses
                try
                {
                    string[] toAddresses = this._toAddresses.Split(';');
                    foreach (string toAddress in toAddresses)
                    {
                        mailMessage.To.Add(new System.Net.Mail.MailAddress(toAddress));
                    }
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring 'to' addresses: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Add list of "cc" addresses
                try
                {
                    if (this._ccAddresses.Length > 0)
                    {
                        string[] ccAddresses = this._ccAddresses.Split(';');
                        foreach (string ccAddress in ccAddresses)
                        {
                            mailMessage.CC.Add(new System.Net.Mail.MailAddress(ccAddress));
                        }
                    }
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring 'cc' addresses: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Add list of "bcc" addresses
                try
                {
                    if (this._bccAddresses.Length > 0)
                    {
                        string[] bccAddresses = this._bccAddresses.Split(';');
                        foreach (string bccAddress in bccAddresses)
                        {
                            mailMessage.Bcc.Add(new System.Net.Mail.MailAddress(bccAddress));
                        }
                    }
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring 'bcc' addresses: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Add Subject
                try
                {
                    mailMessage.Subject = this._subject;
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring subject: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Add Body
                try
                {
                    mailMessage.IsBodyHtml = (this._bodyContentType == BodyContentType.HTML);
                    if (this._bodySourceType == BodySourceType.Direct)
                    {
                        mailMessage.Body = this._body;
                    }
                    else
                    {
                        Variables vars = null;
                        variableDispenser.LockForRead(this._body);
                        variableDispenser.GetVariables(ref vars);
                        mailMessage.Body = (string)vars[0].Value;
                        vars.Unlock();
                    }
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring body: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Attachments
                try
                {
                    if (this._attachments.Length > 0)
                    {
                        string[] fileNames = this._attachments.Split(';');
                        foreach (string fileName in fileNames)
                        {
                            mailMessage.Attachments.Add(new System.Net.Mail.Attachment(fileName));
                        }
                    }
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring attachments: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Add "from" address
                try
                {
                    mailMessage.From = new System.Net.Mail.MailAddress(this._fromAddress);
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring 'from' address: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Set Priority
                try
                {
                    mailMessage.Priority = this._priority;
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while configuring priority: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Retrieve SMTP connection Details
                string smtpServerName;
                try
                {
                    string connectionString = (string)connections[this._smtpConnectionID].AcquireConnection(transaction);
                    string[] connectionStringElements = connectionString.Split(';');
                    string[] smtpServerNameKeyAndValue = connectionStringElements[0].Split('=');
                    smtpServerName = smtpServerNameKeyAndValue[1];
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error while retrieving SMTP Connection Manager information: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion

                #region Send it!
                try
                {
                    System.Net.Mail.SmtpClient smtpClient = new System.Net.Mail.SmtpClient(smtpServerName, 25);
                    //smtpClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                    smtpClient.Send(mailMessage);
                    bool fireAgain = true;
                    componentEvents.FireInformation(0, "Send HTML Mail Task", "Mail sent to " + this._toAddresses + ", subject: " + this._subject, "", 0, ref fireAgain);
                    result = DTSExecResult.Success;
                }
                #region catch ...
                catch (Exception ex)
                {
                    componentEvents.FireError(0, "Send HTML Mail Task",
                        "Execution error sending mail: "
                        + ex.Message, "", 0);
                    throw;
                }
                #endregion
                #endregion
            }
            #region catch ...
            catch (Exception ex)
            {
                componentEvents.FireError(0, "Send HTML Mail Task",
                    "Execution error: "
                    + ex.ToString(), "", 0);
            }
            #endregion

            return result;
        }
        #endregion
        #endregion
    }
}
